// $Id: query.h 9 2008-09-30 03:21:47Z rodlima $

/*
   Copyright (c) 2008, Rodolfo Schulz de Lima 
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

   * Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright notice,
     this list of conditions and the following disclaimer in the documentation
     and/or other materials provided with the distribution.  
   * Neither the name of RodSoft nor the names of its contributors may be used
     to endorse or promote products derived from this software without specific
     prior written permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef ORM_QUERY_H 
#define ORM_QUERY_H

#include "ident.h"
#include "type_traits.h"
#include "nullptr.h"

namespace orm
{
class memberinfo_t;
class metainfo_t;
class transaction;

namespace expr
{

class term/*{{{*/
{
public:
    std::string value(const transaction &xa) const
        { return do_get_term_value(xa); }

    std::unique_ptr<term> move()
        { return std::unique_ptr<term>(do_move()); }
    std::unique_ptr<term> clone() const
        { return std::unique_ptr<term>(do_clone()); }

    virtual ~term() {}

private:
    virtual std::string do_get_term_value(const transaction &xa) const = 0;
    virtual term *do_clone() const = 0;
    virtual term *do_move() = 0;
};/*}}}*/
class unary_term : public term/*{{{*/
{
public:
    unary_term(std::unique_ptr<term> &&term, const std::string &op, bool parentheses=true) 
        : m_term(std::move(term))
        , m_op(op)
        , m_parentheses(parentheses) {}

    unary_term(const unary_term &that)
        : m_term(that.m_term->clone())
        , m_op(that.m_op)
        , m_parentheses(that.m_parentheses) {}
    unary_term(unary_term &&that)
        : m_term(std::move(that.m_term))
        , m_op(std::move(that.m_op))
        , m_parentheses(that.m_parentheses) {}

private:
    std::unique_ptr<term> m_term;
    std::string m_op;
    bool m_parentheses;
    virtual std::string do_get_term_value(const transaction &xa) const;
    virtual unary_term *do_move()
    {
        return new unary_term(std::move(*this));
    }
    virtual unary_term *do_clone() const
    {
        return new unary_term(*this);
    }
};/*}}}*/
class binary_term : public term/*{{{*/
{
public:
    binary_term(std::unique_ptr<term> &&term1, std::unique_ptr<term> &&term2, const std::string &op, bool parentheses=true) 
        : m_term1(std::move(term1))
        , m_term2(std::move(term2))
        , m_op(op)
        , m_parentheses(parentheses) {}

    binary_term(binary_term &&that)
        : m_term1(std::move(that.m_term1))
        , m_term2(std::move(that.m_term2))
        , m_op(std::move(that.m_op))
        , m_parentheses(that.m_parentheses) {}
    binary_term(const binary_term &that)
        : m_term1(that.m_term1->clone())
        , m_term2(that.m_term2->clone())
        , m_op(that.m_op)
        , m_parentheses(that.m_parentheses) {}

private:
    std::unique_ptr<term> m_term1, m_term2;
    std::string m_op;
    bool m_parentheses;

    virtual std::string do_get_term_value(const transaction &xa) const;
    virtual binary_term *do_move()
    {
        return new binary_term(std::move(*this));
    }
    virtual binary_term *do_clone() const
    {
        return new binary_term(*this);
    }
};/*}}}*/

class factor /*{{{*/
{
public:
    std::string value(const transaction &xa) const
        { return do_get_factor_value(xa); }

    std::unique_ptr<factor> move()
        { return std::unique_ptr<factor>(do_move()); }
    std::unique_ptr<factor> clone() const
        { return std::unique_ptr<factor>(do_clone()); }

    virtual ~factor() {}

private:
    virtual std::string do_get_factor_value(const transaction &xa) const = 0;
    virtual factor *do_clone() const = 0;
    virtual factor *do_move() = 0;
};/*}}}*/
class unary_factor : public factor/*{{{*/
{
    struct dummy {};
public:
    unary_factor(std::unique_ptr<factor> &&factor, const std::string &op, bool parentheses=true)
        : m_factor(std::move(factor)), m_op(op), m_parentheses(parentheses) {}

    unary_factor(const unary_factor &that)
        : m_factor(that.m_factor->clone())
        , m_op(that.m_op)
        , m_parentheses(that.m_parentheses) {}

    unary_factor(unary_factor &&that)
        : m_factor(std::move(that.m_factor))
        , m_op(std::move(that.m_op))
        , m_parentheses(that.m_parentheses) {}

private:
    std::unique_ptr<factor> m_factor;
    std::string m_op;
    bool m_parentheses;

    virtual std::string do_get_factor_value(const transaction &xa) const;
    virtual unary_factor *do_move()
    {
        return new unary_factor(std::move(*this));
    }
    virtual unary_factor *do_clone() const
    {
        return new unary_factor(*this);
    }
};/*}}}*/
class binary_factor : public factor/*{{{*/
{
public:
    binary_factor(std::unique_ptr<factor> &&factor1, std::unique_ptr<factor> &&factor2, const std::string &op, bool parentheses=true)
        : m_factor1(std::move(factor1)), m_factor2(std::move(factor2)), m_op(op), m_parentheses(parentheses) {}

    binary_factor(const binary_factor &that)
        : m_factor1(that.m_factor1->clone())
        , m_factor2(that.m_factor2->clone())
        , m_op(that.m_op)
        , m_parentheses(that.m_parentheses) {}

    binary_factor(binary_factor &&that)
        : m_factor1(std::move(that.m_factor1))
        , m_factor2(std::move(that.m_factor2))
        , m_op(std::move(that.m_op))
        , m_parentheses(that.m_parentheses) {}

private:
    std::unique_ptr<factor> m_factor1, m_factor2;
    std::string m_op;
    bool m_parentheses;

    virtual std::string do_get_factor_value(const transaction &xa) const;
    virtual binary_factor *do_move()
    {
        return new binary_factor(std::move(*this));
    }
    virtual binary_factor *do_clone() const
    {
        return new binary_factor(*this);
    }
};/*}}}*/

class set_factor : public factor/*{{{*/
{
public:
    template <class...ARGS> set_factor(std::unique_ptr<ARGS> &&...factors)/*{{{*/
    {
        insert_factors(std::move(factors)...);
    }/*}}}*/

    set_factor(const set_factor &that);

    set_factor(set_factor &&that)
        : m_factors(std::move(that.m_factors)) {}

    size_t size() const { return m_factors.size(); }

protected:
    std::vector<std::unique_ptr<factor>> &factors() { return m_factors; }

private:
    template <class...ARGS> void insert_factors(std::unique_ptr<factor> &&f, std::unique_ptr<ARGS> &&...args)
    {
        m_factors.push_back(std::move(f));
        insert_factors(args...);
    }
    void insert_factors() {};

    std::vector<std::unique_ptr<factor>> m_factors;

    virtual std::string do_get_factor_value(const transaction &xa) const;
    virtual set_factor *do_move()
    {
        return new set_factor(std::move(*this));
    }
    virtual set_factor *do_clone() const
    {
        return new set_factor(*this);
    }
};/*}}}*/
class function_factor : public factor/*{{{*/
{
public:
    template <class...ARGS> function_factor(const std::string &name, std::unique_ptr<ARGS> &&...factors)/*{{{*/
        : m_args(factors...)
        , m_name(name)
    {
    }/*}}}*/

    function_factor(const function_factor &that)
        : m_args(that.m_args)
        , m_name(that.m_name) {}

    function_factor(function_factor &&that)
        : m_args(std::move(that.m_args))
        , m_name(std::move(that.m_name)) {}

private:
    set_factor m_args;
    std::string m_name;

    virtual std::string do_get_factor_value(const transaction &xa) const;
    virtual function_factor *do_move()
    {
        return new function_factor(std::move(*this));
    }
    virtual function_factor *do_clone() const
    {
        return new function_factor(*this);
    }
};/*}}}*/

class factor_binary_term : public term/*{{{*/
{
public:
    factor_binary_term(std::unique_ptr<factor> &&factor1, std::unique_ptr<factor> &&factor2, const std::string &op, bool parentheses=true) 
        : m_factor1(std::move(factor1))
        , m_factor2(std::move(factor2))
        , m_op(op)
        , m_parentheses(parentheses) {}

    factor_binary_term(factor_binary_term &&that)
        : m_factor1(std::move(that.m_factor1))
        , m_factor2(std::move(that.m_factor2))
        , m_op(std::move(that.m_op))
        , m_parentheses(that.m_parentheses) {}
    factor_binary_term(const factor_binary_term &that)
        : m_factor1(that.m_factor1->clone())
        , m_factor2(that.m_factor2->clone())
        , m_op(that.m_op)
        , m_parentheses(that.m_parentheses) {}

private:
    std::unique_ptr<factor> m_factor1, m_factor2;
    std::string m_op;
    bool m_parentheses;

    virtual std::string do_get_term_value(const transaction &xa) const;
    virtual factor_binary_term *do_move()
    {
        return new factor_binary_term(std::move(*this));
    }
    virtual factor_binary_term *do_clone() const
    {
        return new factor_binary_term(*this);
    }
};/*}}}*/

template <class T> class constant : public factor/*{{{*/
{
public:
    explicit constant(const T &value) : m_value(value) {}
    constant(const constant &that)
        : m_value(that.m_value) {}
    constant(constant &&that)
        : m_value(std::move(that.m_value)) {}
private:
    T m_value;
    virtual std::string do_get_factor_value(const transaction &xa) const
    {
        return to_sql_field(xa, m_value);
    }
    virtual constant *do_move()
    {
        return new constant(std::move(*this));
    }
    virtual constant *do_clone() const
    {
        return new constant(*this);
    }
};/*}}}*/
template <> class constant<bool> : public term, public factor/*{{{*/
{
public:
    explicit constant(bool value) : m_value(value) {}
private:
    bool m_value;
    virtual std::string do_get_term_value(const transaction &xa) const
    {
        return to_sql_field(xa, m_value);
    }
    virtual std::string do_get_factor_value(const transaction &xa) const
    {
        return to_sql_field(xa, m_value);
    }
    virtual constant *do_move()
    {
        return new constant(m_value);
    }
    virtual constant *do_clone() const
    {
        return new constant(m_value);
    }
};/*}}}*/
template <> class constant<std::nullptr_t> : public factor/*{{{*/
{
public:
    explicit constant() {}
private:
    virtual std::string do_get_factor_value(const transaction &xa) const
    {
        return "NULL";
    }
    virtual constant *do_move()
    {
        return new constant(std::move(*this));
    }
    virtual constant *do_clone() const
    {
        return new constant(*this);
    }
};/*}}}*/

class member_base/*{{{*/
{
public:
    template <class R, class T> member_base(R T::*field)
    {
        m_member = T::meta.get_member(field);
        if(m_member == NULL)
            throw std::runtime_error("member not defined in object "+T::meta.table_name());

    }
    virtual ~member_base() {}
protected:
    member_base(const member_base &that)
        : m_member(that.m_member) {}
    virtual std::string get_value(const transaction &xa) const;

private:
    const memberinfo_t *m_member;
};/*}}}*/
template <class R> class member : public member_base, public factor/*{{{*/
{
public:
    template <class T> member(R T::*field)
        : member_base(field) {}
private:

    virtual std::string do_get_factor_value(const transaction &xa) const
    {
        return member_base::get_value(xa);
    }
    virtual member *do_move()
    {
        return new member(std::move(*this));
    }
    virtual member *do_clone() const
    {
        return new member(*this);
    }
};/*}}}*/
template <> class member<bool> : public member_base, public term, public factor/*{{{*/
{
public:
    template <class T> member(bool T::*field)
        : member_base(field) {}
private:

    virtual std::string do_get_factor_value(const transaction &xa) const
    {
        return member_base::get_value(xa);
    }
    virtual std::string do_get_term_value(const transaction &xa) const
    {
        return member_base::get_value(xa);
    }
    virtual member *do_move()
    {
        return new member(std::move(*this));
    }
    virtual member *do_clone() const
    {
        return new member(*this);
    }
};/*}}}*/
template <class R> class member<boost::optional<R>> : public member_base, public term, public factor/*{{{*/
{
public:
    template <class T> member(boost::optional<R> T::*field)
        : member_base(field) {}
private:
    virtual std::string do_get_term_value(const transaction &xa) const
    {
        std::ostringstream ss;
        ss << "(" << member_base::get_value(xa) + " IS NOT NULL)";
        return ss.str();
    }
    virtual std::string do_get_factor_value(const transaction &xa) const
    {
        return member_base::get_value(xa);
    }
    virtual member *do_move()
    {
        return new member(std::move(*this));
    }
    virtual member *do_clone() const
    {
        return new member(*this);
    }
};/*}}}*/

class value/*{{{*/
{
    struct dummy {};
public:
    template <class T> value(T &&val, typename std::enable_if<type_traits<T>::is_specialized,dummy>::type =dummy())
        : m_factor(new constant<typename type_traits<T>::type>(std::forward<T>(val))) {}

    template <class T, class C> value(T C::*val, typename std::enable_if<type_traits<T>::is_specialized,dummy>::type =dummy())
        : m_factor(new member<typename type_traits<T>::type>(val)) {}

    value(factor &&factor) : m_factor(factor.move()) {}

    value(const value &that) : m_factor(that.m_factor->clone()) {}
    value(value &&that) : m_factor(std::move(that.m_factor)) {}
    virtual ~value() {}

    std::unique_ptr<factor> &get_factor() { return m_factor; }

private:
    std::unique_ptr<factor> m_factor;
};/*}}}*/
class equality_comparable/*{{{*/
{
    struct dummy {};
public:
    equality_comparable(const std::nullptr_t &)
        : m_factor(new constant<std::nullptr_t>())
        , m_equal("IS"), m_notequal("IS NOT") {}

    template <class T> equality_comparable(T &&val, const std::string &eq="=", const std::string &neq="<>", typename std::enable_if<type_traits<T>::is_specialized,dummy>::type =dummy())
        : m_factor(new constant<typename type_traits<T>::type>(std::forward<T>(val)))
        , m_equal(eq), m_notequal(neq) {}

    template <class T, class C> equality_comparable(T C::*val, typename std::enable_if<type_traits<T>::is_specialized,dummy>::type =dummy())
        : m_factor(new member<T>(val))
        , m_equal("="), m_notequal("<>") {}

    equality_comparable(factor &&factor, const std::string &eq="=", const std::string &neq="<>") 
        : m_factor(factor.move()), m_equal(eq), m_notequal(neq) {}

    equality_comparable(equality_comparable &&that)
        : m_factor(std::move(that.m_factor))
        , m_equal(std::move(that.m_equal))
        , m_notequal(std::move(that.m_notequal)) {}

    std::string equal_op() const { return m_equal; }
    std::string not_equal_op() const { return m_notequal; }

    std::unique_ptr<factor> &get_factor() { return m_factor; }
private:
    std::unique_ptr<factor> m_factor;
    std::string m_equal, m_notequal;
};/*}}}*/
class less_than_comparable/*{{{*/
{
    struct dummy {};
public:
    template <class T> less_than_comparable(T &&val, typename std::enable_if<type_traits<T>::is_specialized,dummy>::type =dummy())
        : m_factor(new constant<typename type_traits<T>::type>(std::forward<T>(val)))
        , m_lt("<"), m_gt(">"), m_let("<="), m_get(">=") {}

    template <class T, class C> less_than_comparable(T C::*val, typename std::enable_if<type_traits<T>::is_specialized,dummy>::type =dummy())
        : m_factor(new member<T>(val))
        , m_lt("<"), m_gt(">"), m_let("<="), m_get(">=") {}

    less_than_comparable(factor &&factor) 
        : m_factor(factor.move())
        , m_lt("<"), m_gt(">"), m_let("<="), m_get(">=") {}

    less_than_comparable(less_than_comparable &&that)
        : m_factor(std::move(that.m_factor))
        , m_lt(std::move(that.m_lt))
        , m_gt(std::move(that.m_gt))
        , m_let(std::move(that.m_let))
        , m_get(std::move(that.m_get)) {}

    std::string less_than_op() const { return m_lt; }
    std::string greater_than_op() const { return m_gt; }
    std::string less_or_equal_than_op() const { return m_let; }
    std::string greater_or_equal_than_op() const { return m_get; }

    std::unique_ptr<factor> &get_factor() { return m_factor; }
private:
    std::unique_ptr<factor> m_factor;
    std::string m_lt, m_gt, m_let, m_get;
};/*}}}*/
class boolean_comparable/*{{{*/
{
    struct dummy {};
public:
    boolean_comparable(term &&val)
        : m_term(val.move()) {}

    boolean_comparable(bool val)
        : m_term(new constant<bool>(val)) {}

    template <class C> boolean_comparable(bool C::*val)
        : m_term(new member<bool>(val)) {}

    boolean_comparable(boolean_comparable &&that)
        : m_term(std::move(that.m_term)) {}

    std::unique_ptr<term> &get_term() { return m_term; }
private:
    std::unique_ptr<term> m_term;
};/*}}}*/

} // namespace expr

expr::binary_term operator&&(expr::boolean_comparable &&b1, expr::boolean_comparable &&b2);
expr::binary_term operator||(expr::boolean_comparable &&b1, expr::boolean_comparable &&b2);
expr::unary_term operator!(expr::boolean_comparable &&b);

expr::factor_binary_term operator==(expr::value &&f1, expr::equality_comparable &&f2);
expr::factor_binary_term operator!=(expr::value &&f1, expr::equality_comparable &&f2);
expr::factor_binary_term operator>(expr::value &&f1, expr::less_than_comparable &&f2);
expr::factor_binary_term operator<(expr::value &&f1, expr::less_than_comparable &&f2);
expr::factor_binary_term operator>=(expr::value &&f1, expr::less_than_comparable &&f2);
expr::factor_binary_term operator<=(expr::value &&f1, expr::less_than_comparable &&f2);

expr::binary_factor operator+(expr::value &&f1, expr::value &&f2);
expr::binary_factor operator-(expr::value &&f1, expr::value &&f2);
expr::unary_factor operator-(expr::value &&f1);
expr::binary_factor operator*(expr::value &&f1, expr::value &&f2);
expr::binary_factor operator/(expr::value &&f1, expr::value &&f2);
expr::binary_factor operator%(expr::value &&f1, expr::value &&f2);
expr::binary_factor operator^(expr::value &&f1, expr::value &&f2);
expr::binary_factor operator&(expr::value &&f1, expr::value &&f2);
expr::binary_factor operator|(expr::value &&f1, expr::value &&f2);
expr::unary_factor operator~(expr::value &&f1);
expr::binary_factor operator<<(expr::value &&f1, expr::value &&f2);
expr::binary_factor operator>>(expr::value &&f1, expr::value &&f2);

template <class R, class T> expr::member<R> member(R T::*member)/*{{{*/
{
    return expr::member<R>(member);
}/*}}}*/
expr::equality_comparable like(const std::string &str);
expr::equality_comparable ilike(const std::string &str);
expr::equality_comparable similar(const std::string &str);
expr::equality_comparable between(expr::value &&val1, expr::value &&val2);
template <class... ARGS> expr::equality_comparable in(ARGS &&...args)
{
    static_assert(sizeof...(args) > 0, "Cannot create an empty set");

    return expr::equality_comparable(expr::set_factor(expr::value(args).get_factor()...), "IN", "NOT IN");
}

expr::function_factor sin(expr::value &&val);
expr::function_factor cos(expr::value &&val);
expr::function_factor tan(expr::value &&val);
expr::function_factor acos(expr::value &&val);
expr::function_factor asin(expr::value &&val);
expr::function_factor atan(expr::value &&val);
expr::function_factor atan2(expr::value &&val1, expr::value &&val2);

expr::function_factor pow(expr::value &&val1, expr::value &&val2);
expr::function_factor abs(expr::value &&val);
expr::function_factor ceil(expr::value &&val);
expr::function_factor floor(expr::value &&val);
expr::function_factor degrees(expr::value &&val);
expr::function_factor exp(expr::value &&val);
expr::function_factor log(expr::value &&val);
expr::function_factor log10(expr::value &&val);
expr::function_factor radians(expr::value &&val);
expr::function_factor round(expr::value &&val);
expr::function_factor sign(expr::value &&val);
expr::function_factor sqrt(expr::value &&val);
expr::function_factor trunc(expr::value &&val);

expr::function_factor strlen(expr::value &&val);
expr::binary_factor strcat(expr::value &&val1,expr::value &&val2);
expr::function_factor strlwr(expr::value &&val);
expr::function_factor strupr(expr::value &&val);
expr::function_factor strtrim(expr::value &&val);
expr::function_factor md5(expr::value &&val);

} // namespace orm

#endif

